bitkeeper revision 1.165.1.1 (3e9c3ccaCJe7Z8jxplsENPEQ5oFIFw)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 15 Apr 2003 17:09:30 +0000 (17:09 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Tue, 15 Apr 2003 17:09:30 +0000 (17:09 +0000)
Many files:
  Partial checkin of virtualised LDT support.

22 files changed:
xen/arch/i386/mm.c
xen/arch/i386/process.c
xen/arch/i386/traps.c
xen/common/memory.c
xen/include/asm-i386/desc.h
xen/include/asm-i386/system.h
xen/include/xeno/config.h
xen/include/xeno/mm.h
xen/include/xeno/sched.h
xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/entry.S
xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/head.S
xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/ldt.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/process.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/setup.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/kernel/traps.c
xenolinux-2.4.21-pre4-sparse/arch/xeno/mm/hypervisor.c
xenolinux-2.4.21-pre4-sparse/include/asm-xeno/desc.h
xenolinux-2.4.21-pre4-sparse/include/asm-xeno/hypervisor.h
xenolinux-2.4.21-pre4-sparse/include/asm-xeno/mmu_context.h
xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgalloc.h
xenolinux-2.4.21-pre4-sparse/include/asm-xeno/pgtable.h
xenolinux-2.4.21-pre4-sparse/include/asm-xeno/processor.h

index c18d088cfd03e0c103e29e478c114991f07dab9c..2eeaf928d6005832cd596c6d56e35adec0e608f2 100644 (file)
@@ -116,12 +116,12 @@ long do_stack_switch(unsigned long ss, unsigned long esp)
 
 
 /* Returns TRUE if given descriptor is valid for GDT or LDT. */
-static int check_descriptor(unsigned long a, unsigned long b)
+int check_descriptor(unsigned long a, unsigned long b)
 {
     unsigned long base, limit;
 
     /* A not-present descriptor will always fault, so is safe. */
-    if ( !(a & _SEGMENT_P) ) 
+    if ( !(b & _SEGMENT_P) ) 
         goto good;
 
     /*
@@ -130,10 +130,10 @@ static int check_descriptor(unsigned long a, unsigned long b)
      * gates (consider a call gate pointing at another guestos descriptor with 
      * DPL 0 -- this would get the OS ring-0 privileges).
      */
-    if ( (a & _SEGMENT_DPL) == 0 )
+    if ( (b & _SEGMENT_DPL) == 0 )
         goto bad;
 
-    if ( !(a & _SEGMENT_S) )
+    if ( !(b & _SEGMENT_S) )
     {
         /*
          * System segment:
@@ -148,15 +148,15 @@ static int check_descriptor(unsigned long a, unsigned long b)
          */
 
         /* Disallow everything but call gates. */
-        if ( (a & _SEGMENT_TYPE) != 0xc00 )
+        if ( (b & _SEGMENT_TYPE) != 0xc00 )
             goto bad;
 
         /* Can't allow far jump to a Xen-private segment. */
-        if ( !VALID_CODESEL(b>>16) )
+        if ( !VALID_CODESEL(a>>16) )
             goto bad;
 
         /* Reserved bits must be zero. */
-        if ( (a & 0xe0) != 0 )
+        if ( (b & 0xe0) != 0 )
             goto bad;
         
         /* No base/limit check is needed for a call gate. */
@@ -164,10 +164,10 @@ static int check_descriptor(unsigned long a, unsigned long b)
     }
     
     /* Check that base/limit do not overlap Xen-private space. */
-    base  = (a&(0xff<<24)) | ((a&0xff)<<16) | (b>>16);
-    limit = (a&0xf0000) | (b&0xffff);
+    base  = (b&(0xff<<24)) | ((b&0xff)<<16) | (a>>16);
+    limit = (b&0xf0000) | (a&0xffff);
     limit++; /* We add one because limit is inclusive. */
-    if ( (a & _SEGMENT_G) )
+    if ( (b & _SEGMENT_G) )
         limit <<= 12;
     if ( ((base + limit) <= base) || 
          ((base + limit) >= PAGE_OFFSET) )
@@ -214,7 +214,7 @@ long do_set_gdt(unsigned long *frame_list, unsigned int entries)
             /* Check all potential GDT entries in the page. */
             gdt_page = map_domain_mem(frames[0] << PAGE_SHIFT);
             for ( i = 0; i < 512; i++ )
-                if ( !check_descriptor(gdt_page[i*2], gdt_page[i*2]+1) )
+                if ( !check_descriptor(gdt_page[i*2], gdt_page[i*2+1]) )
                     goto out;
             unmap_domain_mem(gdt_page);
         }
@@ -247,9 +247,9 @@ long do_set_gdt(unsigned long *frame_list, unsigned int entries)
     flush_tlb();
 
     /* Copy over first entries of the new GDT. */
-    memcpy((void *)PERDOMAIN_VIRT_START, gdt_table, FIRST_DOMAIN_GDT_ENTRY*8);
+    memcpy((void *)GDT_VIRT_START, gdt_table, FIRST_DOMAIN_GDT_ENTRY*8);
     
-    SET_GDT_ADDRESS(current, PERDOMAIN_VIRT_START);
+    SET_GDT_ADDRESS(current, GDT_VIRT_START);
     SET_GDT_ENTRIES(current, (entries*8)-1);
     __asm__ __volatile__ ("lgdt %0" : "=m" (*current->mm.gdt));
 
index 05a475e11d49d937b0dddf0557e5d0765cd78332..3affffcdc8ac6b55a372bc615ab55aec42f8cf4a 100644 (file)
@@ -216,25 +216,6 @@ void show_regs(struct pt_regs * regs)
     show_trace(&regs->esp);
 }
 
-/*
- * No need to lock the MM as we are the last user
- */
-void release_segments(struct mm_struct *mm)
-{
-#if 0
-    void * ldt = mm.context.segments;
-
-    /*
-     * free the LDT
-     */
-    if (ldt) {
-        mm.context.segments = NULL;
-        clear_LDT();
-        vfree(ldt);
-    }
-#endif
-}
-
 
 /*
  * Free current thread data structures etc..
@@ -258,48 +239,8 @@ void flush_thread(void)
 
 void release_thread(struct task_struct *dead_task)
 {
-#if 0
-    if (dead_task->mm) {
-        void * ldt = dead_task->mm.context.segments;
-
-        // temporary debugging check
-        if (ldt) {
-            printk("WARNING: dead process %8s still has LDT? <%p>\n",
-                   dead_task->comm, ldt);
-            BUG();
-        }
-    }
-#endif
-}
-
-/*
- * we do not have to muck with descriptors here, that is
- * done in switch_mm() as needed.
- */
-void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
-{
-#if 0
-    struct mm_struct * old_mm;
-    void *old_ldt, *ldt;
-
-    ldt = NULL;
-    old_mm = current->mm;
-    if (old_mm && (old_ldt = old_mm.context.segments) != NULL) {
-        /*
-         * Completely new LDT, we initialize it from the parent:
-         */
-        ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
-        if (!ldt)
-            printk(KERN_WARNING "ldt allocation failed\n");
-        else
-            memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
-    }
-    new_mm.context.segments = ldt;
-    new_mm.context.cpuvalid = ~0UL;    /* valid on all CPU's - they can't have stale data */
-#endif
 }
 
-
 void new_thread(struct task_struct *p,
                 unsigned long start_pc,
                 unsigned long start_stack,
@@ -395,7 +336,7 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 
     /* Switch GDT and LDT. */
     __asm__ __volatile__ ("lgdt %0" : "=m" (*next_p->mm.gdt));
-//    __load_LDT(0);
+    load_LDT();
 
     /*
      * Restore %fs and %gs.
index f0b15e081f4fe1beda48e39ba86466871cac22d9..a58bfc1d734bf5c4787f227d24adecae8e6e5d3b 100644 (file)
@@ -17,7 +17,7 @@
 #include <xeno/delay.h>
 #include <xeno/spinlock.h>
 #include <xeno/irq.h>
-
+#include <asm/domain_page.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/atomic.h>
@@ -188,22 +188,13 @@ static void inline do_trap(int trapnr, char *str,
 {
     struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
     trap_info_t *ti;
-    unsigned long addr, fixup;
+    unsigned long fixup;
 
     if (!(regs->xcs & 3))
         goto fault_in_hypervisor;
 
     ti = current->thread.traps + trapnr;
-    if ( trapnr == 14 )
-    {
-        /* page fault pushes %cr2 */
-        gtb->flags = GTBF_TRAP_CR2;
-        __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (gtb->cr2) : );
-    }
-    else
-    {
-        gtb->flags = use_error_code ? GTBF_TRAP : GTBF_TRAP_NOCODE;
-    }
+    gtb->flags = use_error_code ? GTBF_TRAP : GTBF_TRAP_NOCODE;
     gtb->error_code = error_code;
     gtb->cs         = ti->cs;
     gtb->eip        = ti->address;
@@ -217,29 +208,10 @@ static void inline do_trap(int trapnr, char *str,
         return;
     }
 
-    __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (addr) : );
-
-    if ( (trapnr == 14) && (addr >= PAGE_OFFSET) )
-    {
-        unsigned long page;
-        unsigned long *pde;
-        pde = (unsigned long *)idle_pg_table[smp_processor_id()];
-        page = pde[addr >> L2_PAGETABLE_SHIFT];
-        printk("*pde = %08lx\n", page);
-        if ( page & _PAGE_PRESENT )
-        {
-            page &= PAGE_MASK;
-            page = ((unsigned long *) __va(page))[(addr&0x3ff000)>>PAGE_SHIFT];
-            printk(" *pte = %08lx\n", page);
-        }
-    }
-
     show_registers(regs);
     panic("CPU%d FATAL TRAP: vector = %d (%s)\n"
-          "[error_code=%08x]\n"
-          "Faulting linear address might be %08lx\n",
-          smp_processor_id(), trapnr, str,
-          error_code, addr);
+          "[error_code=%08x]\n",
+          smp_processor_id(), trapnr, str, error_code);
 }
 
 #define DO_ERROR_NOCODE(trapnr, str, name) \
@@ -265,14 +237,134 @@ DO_ERROR_NOCODE( 9, "coprocessor segment overrun", coprocessor_segment_overrun)
 DO_ERROR(10, "invalid TSS", invalid_TSS)
 DO_ERROR(11, "segment not present", segment_not_present)
 DO_ERROR(12, "stack segment", stack_segment)
-DO_ERROR(14, "page fault", page_fault)
 /* Vector 15 reserved by Intel */
 DO_ERROR_NOCODE(16, "fpu error", coprocessor_error)
 DO_ERROR(17, "alignment check", alignment_check)
 DO_ERROR_NOCODE(18, "machine check", machine_check)
 DO_ERROR_NOCODE(19, "simd error", simd_coprocessor_error)
 
-asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
+asmlinkage void do_page_fault(struct pt_regs *regs, long error_code)
+{
+    struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
+    trap_info_t *ti;
+    l2_pgentry_t *pl2e;
+    l1_pgentry_t *pl1e;
+    unsigned long addr, off, fixup, l2e, l1e, *ldt_page;
+    struct task_struct *p = current;
+    struct pfn_info *page;
+    int i;
+
+    __asm__ __volatile__ ("movl %%cr2,%0" : "=r" (addr) : );
+
+    if ( unlikely(!(regs->xcs & 3)) )
+        goto fault_in_hypervisor;
+
+    if ( unlikely(addr > PAGE_OFFSET) )
+        goto fault_in_xen_space;
+
+ bounce_fault:
+
+    if ( (regs->xcs &3) == 1 )
+        printk("Fault at %08x (%08x)\n", addr, regs->eip); /* XXX */
+
+    ti = p->thread.traps + 14;
+    gtb->flags = GTBF_TRAP_CR2; /* page fault pushes %cr2 */
+    gtb->cr2        = addr;
+    gtb->error_code = error_code;
+    gtb->cs         = ti->cs;
+    gtb->eip        = ti->address;
+    return; 
+
+
+ fault_in_xen_space:
+
+    if ( (addr < LDT_VIRT_START) || 
+         (addr >= (LDT_VIRT_START + (p->mm.ldt_ents*LDT_ENTRY_SIZE))) )
+        goto bounce_fault;
+
+    off  = addr - LDT_VIRT_START;
+    addr = p->mm.ldt_base + off;
+
+    spin_lock_irq(&p->page_lock);
+
+    pl2e  = map_domain_mem(pagetable_val(p->mm.pagetable));
+    l2e   = l2_pgentry_val(pl2e[l2_table_offset(addr)]);
+    unmap_domain_mem(pl2e);
+    if ( !(l2e & _PAGE_PRESENT) )
+        goto unlock_and_bounce_fault;
+
+    pl1e  = map_domain_mem(l2e & PAGE_MASK);
+    l1e   = l1_pgentry_val(pl1e[l1_table_offset(addr)]);
+    unmap_domain_mem(pl1e);
+    if ( !(l1e & _PAGE_PRESENT) )
+        goto unlock_and_bounce_fault;
+
+    page = frame_table + (l1e >> PAGE_SHIFT);
+    if ( (page->flags & PG_type_mask) != PGT_ldt_page )
+    {
+        if ( page->type_count != 0 )
+        { /* XXX */
+            printk("BOGO TYPE %08lx %ld\n", page->flags, page->type_count);
+            goto unlock_and_bounce_fault;
+        }
+        /* Check all potential LDT entries in the page. */
+        ldt_page = map_domain_mem(l1e & PAGE_MASK);
+        for ( i = 0; i < 512; i++ )
+            if ( !check_descriptor(ldt_page[i*2], ldt_page[i*2+1]) )
+            { /* XXX */
+                printk("Bad desc!!!!!\n");
+                goto unlock_and_bounce_fault;
+            }
+        unmap_domain_mem(ldt_page);
+        page->flags &= ~PG_type_mask;
+        page->flags |= PGT_ldt_page;
+        get_page_type(page);
+        get_page_tot(page);
+    }
+
+    p->mm.perdomain_pt[l1_table_offset(off)+16] = mk_l1_pgentry(l1e);
+
+    spin_unlock_irq(&p->page_lock);
+    return;
+
+
+ unlock_and_bounce_fault:
+
+    spin_unlock_irq(&p->page_lock);
+    goto bounce_fault;
+
+
+ fault_in_hypervisor:
+
+    if ( (fixup = search_exception_table(regs->eip)) != 0 )
+    {
+        regs->eip = fixup;
+        return;
+    }
+
+    if ( addr >= PAGE_OFFSET )
+    {
+        unsigned long page;
+        unsigned long *pde;
+        pde = (unsigned long *)idle_pg_table[smp_processor_id()];
+        page = pde[addr >> L2_PAGETABLE_SHIFT];
+        printk("*pde = %08lx\n", page);
+        if ( page & _PAGE_PRESENT )
+        {
+            page &= PAGE_MASK;
+            page = ((unsigned long *) __va(page))[(addr&0x3ff000)>>PAGE_SHIFT];
+            printk(" *pte = %08lx\n", page);
+        }
+    }
+
+    show_registers(regs);
+    panic("CPU%d FATAL PAGE FAULT\n"
+          "[error_code=%08x]\n"
+          "Faulting linear address might be %08lx\n",
+          smp_processor_id(), error_code, addr);
+}
+
+asmlinkage void do_general_protection(struct pt_regs *regs, long error_code)
 {
     struct guest_trap_bounce *gtb = guest_trap_bounce+smp_processor_id();
     trap_info_t *ti;
@@ -315,7 +407,7 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
             return;
         }
     }
-
+    
     /* Pass on GPF as is. */
     ti = current->thread.traps + 13;
     gtb->flags      = GTBF_TRAP;
@@ -328,6 +420,7 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
 
     if ( (fixup = search_exception_table(regs->eip)) != 0 )
     {
+        printk("Hmmmm %08lx -> %08lx (%04lx)\n", regs->eip, fixup, error_code);
         regs->eip = fixup;
         return;
     }
index c39b1ae862b7507f7e30c9371d504e06cd5d9323..b7daecbf93d8dbd490c9c014440cf14144c62007 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/domain_page.h>
 
-#if 0
+#if 1
 #define MEM_LOG(_f, _a...) printk("DOM%d: (file=memory.c, line=%d) " _f "\n", current->domain, __LINE__, ## _a )
 #else
 #define MEM_LOG(_f, _a...) ((void)0)
@@ -621,10 +621,15 @@ static int mod_l1_entry(unsigned long pa, l1_pgentry_t new_l1_entry)
 static int do_extended_command(unsigned long ptr, unsigned long val)
 {
     int err = 0;
+    unsigned int cmd = val & PGEXT_CMD_MASK;
     unsigned long pfn = ptr >> PAGE_SHIFT;
     struct pfn_info *page = frame_table + pfn;
 
-    switch ( (val & PGEXT_CMD_MASK) )
+    /* 'ptr' must be in range except where it isn't a machine address. */
+    if ( (pfn >= max_page) && (cmd != PGEXT_SET_LDT) )
+        return 1;
+
+    switch ( cmd )
     {
     case PGEXT_PIN_L1_TABLE:
         err = get_l1_table(pfn);
@@ -695,6 +700,42 @@ static int do_extended_command(unsigned long ptr, unsigned long val)
         __flush_tlb_one(val & ~PGEXT_CMD_MASK);
         break;
 
+    case PGEXT_SET_LDT:
+    {
+        int i;
+        unsigned long ents = val >> PGEXT_CMD_SHIFT;
+        if ( ((ptr & (PAGE_SIZE-1)) != 0) || 
+             (ents > 8192) ||
+             ((ptr+ents*LDT_ENTRY_SIZE) < ptr) ||
+             ((ptr+ents*LDT_ENTRY_SIZE) > PAGE_OFFSET) )
+        {
+            err = 1;
+            MEM_LOG("Bad args to SET_LDT: ptr=%08lx, ents=%08lx", ptr, ents);
+        }
+        else if ( (current->mm.ldt_ents != ents) || 
+                  (current->mm.ldt_base != ptr) )
+        {
+            if ( current->mm.ldt_ents != 0 )
+            {
+                /* Tear down the old LDT. */
+                for ( i = 16; i < 32; i++ )
+                {
+                    pfn = l1_pgentry_to_pagenr(current->mm.perdomain_pt[i]);
+                    if ( pfn == 0 ) continue;
+                    current->mm.perdomain_pt[i] = mk_l1_pgentry(0);
+                    page = frame_table + pfn;
+                    put_page_type(page);
+                    put_page_tot(page);                
+                }
+                tlb_flush[smp_processor_id()] = 1;
+            }
+            current->mm.ldt_base = ptr;
+            current->mm.ldt_ents = ents;
+            load_LDT();
+        }
+        break;
+    }
+
     default:
         MEM_LOG("Invalid extended pt command 0x%08lx", val & PGEXT_CMD_MASK);
         err = 1;
@@ -710,6 +751,7 @@ int do_process_page_updates(page_update_request_t *ureqs, int count)
     unsigned long flags, pfn;
     struct pfn_info *page;
     int err = 0, i;
+    unsigned int cmd;
 
     for ( i = 0; i < count; i++ )
     {
@@ -718,8 +760,11 @@ int do_process_page_updates(page_update_request_t *ureqs, int count)
             kill_domain_with_errmsg("Cannot read page update request");
         } 
 
+        cmd = req.ptr & (sizeof(l1_pgentry_t)-1);
+
+        /* All normal commands must have 'ptr' in range. */
         pfn = req.ptr >> PAGE_SHIFT;
-        if ( pfn >= max_page )
+        if ( (pfn >= max_page) && (cmd != PGREQ_EXTENDED_COMMAND) )
         {
             MEM_LOG("Page out of range (%08lx > %08lx)", pfn, max_page);
             kill_domain_with_errmsg("Page update request out of range");
@@ -729,7 +774,7 @@ int do_process_page_updates(page_update_request_t *ureqs, int count)
 
         /* Least significant bits of 'ptr' demux the operation type. */
         spin_lock_irq(&current->page_lock);
-        switch ( req.ptr & (sizeof(l1_pgentry_t)-1) )
+        switch ( cmd )
         {
             /*
              * PGREQ_NORMAL: Normal update to any level of page table.
index f1d11e33f7be1e7fa1512f1627d0f8e90703da28..6fc0cb7182cdcb996e243e3a50aa50198b600634 100644 (file)
@@ -1,14 +1,15 @@
 #ifndef __ARCH_DESC_H
 #define __ARCH_DESC_H
 
+#define LDT_ENTRY_SIZE 8
+
 #define __FIRST_TSS_ENTRY 8
 #define __FIRST_LDT_ENTRY (__FIRST_TSS_ENTRY+1)
 
 #define __TSS(n) (((n)<<1) + __FIRST_TSS_ENTRY)
 #define __LDT(n) (((n)<<1) + __FIRST_LDT_ENTRY)
 
-#define load_TR(n)  __asm__ __volatile__ ( "ltr  %%ax" : : "a" (__TSS(n)<<3) )
-#define __load_LDT(n) __asm__ __volatile__ ( "lldt %%ax" : : "a" (n) )
+#define load_TR(n)  __asm__ __volatile__ ("ltr  %%ax" : : "a" (__TSS(n)<<3) )
 
 /* Guest OS must provide its own code selectors, or use the one we provide. */
 #define VALID_CODESEL(_s) \
index 1ccce595d80513deb1bd6b98295ab86d754296fa..a24c5894ef083a35b48be6f0f641640c15100a9e 100644 (file)
@@ -33,50 +33,6 @@ extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *n
                      :"memory");                                        \
 } while (0)
 
-#define _set_base(addr,base) do { unsigned long __pr; \
-__asm__ __volatile__ ("movw %%dx,%1\n\t" \
-       "rorl $16,%%edx\n\t" \
-       "movb %%dl,%2\n\t" \
-       "movb %%dh,%3" \
-       :"=&d" (__pr) \
-       :"m" (*((addr)+2)), \
-        "m" (*((addr)+4)), \
-        "m" (*((addr)+7)), \
-         "0" (base) \
-        ); } while(0)
-
-#define _set_limit(addr,limit) do { unsigned long __lr; \
-__asm__ __volatile__ ("movw %%dx,%1\n\t" \
-       "rorl $16,%%edx\n\t" \
-       "movb %2,%%dh\n\t" \
-       "andb $0xf0,%%dh\n\t" \
-       "orb %%dh,%%dl\n\t" \
-       "movb %%dl,%2" \
-       :"=&d" (__lr) \
-       :"m" (*(addr)), \
-        "m" (*((addr)+6)), \
-        "0" (limit) \
-        ); } while(0)
-
-#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
-#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1)>>12 )
-
-static inline unsigned long _get_base(char * addr)
-{
-       unsigned long __base;
-       __asm__("movb %3,%%dh\n\t"
-               "movb %2,%%dl\n\t"
-               "shll $16,%%edx\n\t"
-               "movw %1,%%dx"
-               :"=&d" (__base)
-               :"m" (*((addr)+2)),
-                "m" (*((addr)+4)),
-                "m" (*((addr)+7)));
-       return __base;
-}
-
-#define get_base(ldt) _get_base( ((char *)&(ldt)) )
-
 /*
  * Load a segment. Fall back on loading the zero
  * segment if something goes wrong..
index ec92fa031cd2ea6d56be567c742f27d41926a5b1..85ad44033a3c284aa5fc8fe13c740d32f83f2a14 100644 (file)
 /* Next 4MB of virtual address space used for per-domain mappings (eg. GDT). */
 #define PERDOMAIN_VIRT_START  (DIRECTMAP_VIRT_END)
 #define PERDOMAIN_VIRT_END    (PERDOMAIN_VIRT_START + (4*1024*1024))
+#define GDT_VIRT_START        (PERDOMAIN_VIRT_START)
+#define GDT_VIRT_END          (GDT_VIRT_START + (64*1024))
+#define LDT_VIRT_START        (GDT_VIRT_END)
+#define LDT_VIRT_END          (LDT_VIRT_START + (64*1024))
 /* Penultimate 4MB of virtual address space used for domain page mappings. */
 #define MAPCACHE_VIRT_START   (PERDOMAIN_VIRT_END)
 #define MAPCACHE_VIRT_END     (MAPCACHE_VIRT_START + (4*1024*1024))
index f71255f9710b80d7309b3f2469cb276e515bbdc9..8f75b61f5fca574cf04e95b357ef7f2991db5970 100644 (file)
@@ -134,6 +134,8 @@ extern unsigned int free_pfns;
 extern unsigned long max_page;
 void init_frametable(unsigned long nr_pages);
 
+int check_descriptor(unsigned long a, unsigned long b);
+
 /*
  * The MPT (machine->physical mapping table) is an array of word-sized
  * values, indexed on machine frame number. It is expected that guest OSes
index f67e20983f6adf6fd9183b92317459a5c8fec0cf..e3312a3fdb8391ded9b613795e7ffe257166202f 100644 (file)
@@ -29,8 +29,8 @@ struct mm_struct {
      */
     l1_pgentry_t *perdomain_pt;
     pagetable_t  pagetable;
-    /* Current LDT descriptor. */
-    unsigned long ldt[2];
+    /* Current LDT details. */
+    unsigned long ldt_base, ldt_ents;
     /* Next entry is passed to LGDT on domain switch. */
     char gdt[6];
 };
@@ -283,4 +283,26 @@ void cpu_idle(void);   /* Idle loop. */
 
 extern void update_process_times(int user);
 
+#include <asm/desc.h>
+static inline void load_LDT(void)
+{
+    unsigned int cpu;
+    struct desc_struct *desc;
+    unsigned long ents;
+
+    if ( (ents = current->mm.ldt_ents) == 0 )
+    {
+        __asm__ __volatile__ ( "lldt %%ax" : : "a" (0) );
+    }
+    else
+    {
+        cpu = smp_processor_id();
+        desc = (struct desc_struct *)GET_GDT_ADDRESS(current) + __LDT(cpu);
+        desc->a = ((LDT_VIRT_START&0xffff)<<16) | (ents*8-1);
+        desc->b = (LDT_VIRT_START&(0xff<<24)) | 0x8200 | 
+            ((LDT_VIRT_START&0xff0000)>>16);
+        __asm__ __volatile__ ( "lldt %%ax" : : "a" (__LDT(cpu)<<3) );
+    }
+}
+
 #endif
index 0a6a5374d12107b06e9468d566c1db7a018ef234..0525e2976ee4d5b012811603cd8c83c76d42d591 100644 (file)
@@ -133,6 +133,55 @@ ENOSYS = 38
        movl $-8192, reg; \
        andl %esp, reg
 
+ENTRY(lcall7)
+       pushfl                  # We get a different stack layout with call
+       pushl %eax              # gates, which has to be cleaned up later..
+       SAVE_ALL
+       movl EIP(%esp),%eax     # due to call gates, this is eflags, not eip..
+       movl CS(%esp),%edx      # this is eip..
+       movl EFLAGS(%esp),%ecx  # and this is cs..
+       movl %eax,EFLAGS(%esp)  #
+       andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+       pushl %eax
+       popfl
+       movl %edx,EIP(%esp)     # Now we move them to their "normal" places
+       movl %ecx,CS(%esp)      #
+       movl %esp,%ebx
+       pushl %ebx
+       andl $-8192,%ebx        # GET_CURRENT
+       movl exec_domain(%ebx),%edx     # Get the execution domain
+       movl 4(%edx),%edx       # Get the lcall7 handler for the domain
+       pushl $0x7
+       call *%edx
+       addl $4, %esp
+       popl %eax
+       jmp ret_from_sys_call
+
+ENTRY(lcall27)
+       pushfl                  # We get a different stack layout with call
+       pushl %eax              # gates, which has to be cleaned up later..
+       SAVE_ALL
+       movl EIP(%esp),%eax     # due to call gates, this is eflags, not eip..
+       movl CS(%esp),%edx      # this is eip..
+       movl EFLAGS(%esp),%ecx  # and this is cs..
+       movl %eax,EFLAGS(%esp)  #
+       andl $~(NT_MASK|TF_MASK|DF_MASK), %eax
+       pushl %eax
+       popfl
+       movl %edx,EIP(%esp)     # Now we move them to their "normal" places
+       movl %ecx,CS(%esp)      #
+       movl %esp,%ebx
+       pushl %ebx
+       andl $-8192,%ebx        # GET_CURRENT
+       movl exec_domain(%ebx),%edx     # Get the execution domain
+       movl 4(%edx),%edx       # Get the lcall7 handler for the domain
+       pushl $0x27
+       call *%edx
+       addl $4, %esp
+       popl %eax
+       jmp ret_from_sys_call
+
+        
 ENTRY(ret_from_fork)
        pushl %ebx
        call SYMBOL_NAME(schedule_tail)
index 86a82b13dc20892b14fb38697a7328c2fdd63bc7..a89fd8eda49a7f527dd2eaefcfe0c09c59ad5740 100644 (file)
@@ -57,11 +57,14 @@ ENTRY(stack_start)
 ENTRY(empty_zero_page)
 
 .org 0x2000
+ENTRY(default_ldt)
+
+.org 0x3000
 ENTRY(cpu0_pte_quicklist)
 
-.org 0x2400
+.org 0x3400
 ENTRY(cpu0_pgd_quicklist)
         
-.org 0x2800
+.org 0x3800
 ENTRY(stext)
 ENTRY(_stext)
index 6c9394303694baab9afff4b6f05e568fdb971206..ca89b694bdc83efd9b1e3b332bd0e22d8d1790d1 100644 (file)
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/ldt.h>
+#include <asm/desc.h>
 
 /*
- * XXX KAF (28/7/02): This stuff is only used for DOS emulation, and is
- * the default way of finding current TCB in linuxthreads. Supporting
- * table update svia the hypervisor is feasible, but a hassle: for now,
- * recompiling linuxthreads is the most sensible option.
- * 
- * Oh, this may become an issue depending on what JVM we use for
- * running the xeno-daemon.
+ * read_ldt() is not really atomic - this is not a problem since
+ * synchronization of reads and writes done to the LDT has to be
+ * assured by user-space anyway. Writes are atomic, to protect
+ * the security checks done on new descriptors.
  */
+static int read_ldt(void * ptr, unsigned long bytecount)
+{
+    int err;
+    unsigned long size;
+    struct mm_struct * mm = current->mm;
+
+    err = 0;
+    if (!mm->context.segments)
+        goto out;
+
+    size = LDT_ENTRIES*LDT_ENTRY_SIZE;
+    if (size > bytecount)
+        size = bytecount;
+
+    err = size;
+    if (copy_to_user(ptr, mm->context.segments, size))
+        err = -EFAULT;
+ out:
+    return err;
+}
+
+static int read_default_ldt(void * ptr, unsigned long bytecount)
+{
+    int err;
+    unsigned long size;
+    void *address;
+
+    err = 0;
+    address = &default_ldt[0];
+    size = sizeof(struct desc_struct);
+    if (size > bytecount)
+        size = bytecount;
+
+    err = size;
+    if (copy_to_user(ptr, address, size))
+        err = -EFAULT;
+
+    return err;
+}
+
+static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
+{
+    struct mm_struct * mm = current->mm;
+    __u32 entry_1, entry_2, *lp;
+    unsigned long phys_lp;
+    int error;
+    struct modify_ldt_ldt_s ldt_info;
+
+    error = -EINVAL;
+    if (bytecount != sizeof(ldt_info))
+        goto out;
+    error = -EFAULT;   
+    if (copy_from_user(&ldt_info, ptr, sizeof(ldt_info)))
+        goto out;
+
+    error = -EINVAL;
+    if (ldt_info.entry_number >= LDT_ENTRIES)
+        goto out;
+    if (ldt_info.contents == 3) {
+        if (oldmode)
+            goto out;
+        if (ldt_info.seg_not_present == 0)
+            goto out;
+    }
+
+    down_write(&mm->mmap_sem);
+    if (!mm->context.segments) {
+        void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+        error = -ENOMEM;
+        if (!segments)
+            goto out_unlock;
+        memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
+        make_pages_readonly(segments, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
+        wmb();
+        mm->context.segments = segments;
+        mm->context.cpuvalid = 1UL << smp_processor_id();
+        load_LDT(mm);
+        flush_page_update_queue();
+    }
+
+    lp = (__u32 *)((ldt_info.entry_number<<3) + (char *)mm->context.segments);
+    phys_lp = arbitrary_virt_to_phys(lp);
+
+    /* Allow LDTs to be cleared by the user. */
+    if (ldt_info.base_addr == 0 && ldt_info.limit == 0) {
+        if (oldmode ||
+            (ldt_info.contents == 0            &&
+             ldt_info.read_exec_only == 1      &&
+             ldt_info.seg_32bit == 0           &&
+             ldt_info.limit_in_pages == 0      &&
+             ldt_info.seg_not_present == 1     &&
+             ldt_info.useable == 0 )) {
+            entry_1 = 0;
+            entry_2 = 0;
+            goto install;
+        }
+    }
+
+    entry_1 = ((ldt_info.base_addr & 0x0000ffff) << 16) |
+        (ldt_info.limit & 0x0ffff);
+    entry_2 = (ldt_info.base_addr & 0xff000000) |
+        ((ldt_info.base_addr & 0x00ff0000) >> 16) |
+        (ldt_info.limit & 0xf0000) |
+        ((ldt_info.read_exec_only ^ 1) << 9) |
+        (ldt_info.contents << 10) |
+        ((ldt_info.seg_not_present ^ 1) << 15) |
+        (ldt_info.seg_32bit << 22) |
+        (ldt_info.limit_in_pages << 23) |
+        0x7000;
+    if (!oldmode)
+        entry_2 |= (ldt_info.useable << 20);
+
+    /* Install the new entry ...  */
+ install:
+    HYPERVISOR_update_descriptor(phys_lp, entry_1, entry_2);
+    error = 0;
+
+ out_unlock:
+    up_write(&mm->mmap_sem);
+ out:
+    return error;
+}
 
 asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
 {
-    return -ENOSYS;
+    int ret = -ENOSYS;
+
+    switch (func) {
+    case 0:
+        ret = read_ldt(ptr, bytecount);
+        break;
+    case 1:
+        ret = write_ldt(ptr, bytecount, 1);
+        break;
+    case 2:
+        ret = read_default_ldt(ptr, bytecount);
+        break;
+    case 0x11:
+        ret = write_ldt(ptr, bytecount, 0);
+        break;
+    }
+    return ret;
 }
index 32ce1a66ab091412edfc1261c0b57083d7541347..4dc1273c7bcc75834a9be3b612d5de71a5c20a42 100644 (file)
@@ -140,6 +140,8 @@ void release_segments(struct mm_struct *mm)
     if (ldt) {
         mm->context.segments = NULL;
         clear_LDT();
+        make_pages_writeable(ldt, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
+        flush_page_update_queue();
         vfree(ldt);
     }
 }
@@ -225,10 +227,15 @@ void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
          * Completely new LDT, we initialize it from the parent:
          */
         ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
-        if (!ldt)
+        if ( ldt == NULL )
+        {
             printk(KERN_WARNING "ldt allocation failed\n");
+        }
         else
+        {
             memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
+            make_pages_readonly(ldt, (LDT_ENTRIES*LDT_ENTRY_SIZE)/PAGE_SIZE);
+        }
     }
     new_mm->context.segments = ldt;
     new_mm->context.cpuvalid = ~0UL;   /* valid on all CPU's - they can't have stale data */
@@ -335,6 +342,10 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
     struct thread_struct *prev = &prev_p->thread,
         *next = &next_p->thread;
 
+    __cli();
+
+    MULTICALL_flush_page_update_queue();
+
     /*
      * This is basically 'unlazy_fpu', except that we queue a multicall to 
      * indicate FPU task switch, rather than synchronously trapping to Xen.
@@ -356,7 +367,7 @@ void __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
 
     /* EXECUTE ALL TASK SWITCH XEN SYSCALLS AT THIS POINT. */
     execute_multicall_list();
-    sti(); /* matches 'cli' in switch_mm() */
+    __sti();
 
     /*
      * Save away %fs and %gs. No need to save %es and %ds, as
index 6ac4ff242e7ece553347fde2bb771f6a74b30675..b3fa27fb11ecdee3ca4a2026e2cbb59c86253bd1 100644 (file)
@@ -968,6 +968,9 @@ void __init cpu_init (void)
 
     HYPERVISOR_stack_switch(__KERNEL_DS, current->thread.esp0);
 
+    load_LDT(&init_mm);
+    flush_page_update_queue();
+
     /* Force FPU initialization. */
     current->flags &= ~PF_USEDFPU;
     current->used_math = 0;
index da7cd7413e21e802223c6bbc2def8a389288e10a..a10c07a0ae1b9f46265921353ad3f63381123fee 100644 (file)
@@ -42,6 +42,8 @@
 #include <linux/module.h>
 
 asmlinkage int system_call(void);
+asmlinkage void lcall7(void);
+asmlinkage void lcall27(void);
 
 asmlinkage void divide_error(void);
 asmlinkage void debug(void);
@@ -530,6 +532,26 @@ asmlinkage void math_state_restore(struct pt_regs regs)
        current->flags |= PF_USEDFPU;   /* So we fnsave on switch_to() */
 }
 
+
+#define _set_gate(gate_addr,type,dpl,addr) \
+do { \
+  int __d0, __d1; \
+  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
+       "movw %4,%%dx\n\t" \
+       "movl %%eax,%0\n\t" \
+       "movl %%edx,%1" \
+       :"=m" (*((long *) (gate_addr))), \
+        "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
+       :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
+        "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
+} while (0)
+
+static void __init set_call_gate(void *a, void *addr)
+{
+       _set_gate(a,12,3,addr);
+}
+
+
 static trap_info_t trap_table[] = {
     {  0, 0, __KERNEL_CS, (unsigned long)divide_error                },
     {  1, 0, __KERNEL_CS, (unsigned long)debug                       },
@@ -561,5 +583,15 @@ void __init trap_init(void)
 {
     HYPERVISOR_set_trap_table(trap_table);    
     HYPERVISOR_set_fast_trap(SYSCALL_VECTOR);
+
+    /*
+     * The default LDT is a single-entry callgate to lcall7 for iBCS and a
+     * callgate to lcall27 for Solaris/x86 binaries.
+     */
+    clear_page(&default_ldt[0]);
+    set_call_gate(&default_ldt[0],lcall7);
+    set_call_gate(&default_ldt[4],lcall27);
+    __make_page_readonly(&default_ldt[0]);
+
     cpu_init();
 }
index 93554c34209e434346dc235483fc293a74c4780e..d67ad51dc52c4520c17d2c4b24d7b8be335396e7 100644 (file)
@@ -80,12 +80,6 @@ static void DEBUG_disallow_pt_read(unsigned long pa)
 #endif
 
 
-/*
- * This is the current pagetable base pointer, which is updated
- * on context switch.
- */
-unsigned long pt_baseptr;
-
 /*
  * MULTICALL_flush_page_update_queue:
  *   This is a version of the flush which queues as part of a multicall.
@@ -232,3 +226,13 @@ void queue_pte_unpin(unsigned long ptr)
     increment_index();
     spin_unlock_irqrestore(&update_lock, flags);
 }
+
+void queue_set_ldt(unsigned long ptr, unsigned long len)
+{
+    unsigned long flags;
+    spin_lock_irqsave(&update_lock, flags);
+    update_queue[idx].ptr  = PGREQ_EXTENDED_COMMAND | ptr;
+    update_queue[idx].val  = PGEXT_SET_LDT | (len << PGEXT_CMD_SHIFT);
+    increment_index();
+    spin_unlock_irqrestore(&update_lock, flags);
+}
index 1920de026ad7c41416c6337b3535a780f1937967..c417cbe80779ead1b5ea5973cf37e5bb27e86693 100644 (file)
@@ -3,9 +3,37 @@
 
 #include <asm/ldt.h>
 
-#define __LDT(_X)     (0)
+#ifndef __ASSEMBLY__
 
-#define clear_LDT()   ((void)0)
-#define load_LDT(_mm) ((void)0)
+struct desc_struct {
+       unsigned long a,b;
+};
 
-#endif
+struct Xgt_desc_struct {
+       unsigned short size;
+       unsigned long address __attribute__((packed));
+};
+
+extern struct desc_struct default_ldt[];
+
+static inline void clear_LDT(void)
+{
+    queue_set_ldt((unsigned long)&default_ldt[0], 5);
+}
+
+static inline void load_LDT(struct mm_struct *mm)
+{
+    void *segments = mm->context.segments;
+    int count = LDT_ENTRIES;
+
+    if (!segments) {
+        segments = &default_ldt[0];
+        count = 5;
+    }
+         
+    queue_set_ldt((unsigned long)segments, count);
+}
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ARCH_DESC_H__ */
index 35de4c20eb71e023a7c46189422ceef60a5f794c..b7dfb52e204e186915cf7b0cf30c47436a230a81 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <asm/hypervisor-ifs/hypervisor-if.h>
 #include <asm/ptrace.h>
+#include <asm/page.h>
 
 /* arch/xeno/kernel/setup.c */
 union start_info_union
@@ -42,7 +43,7 @@ void queue_pgd_pin(unsigned long ptr);
 void queue_pgd_unpin(unsigned long ptr);
 void queue_pte_pin(unsigned long ptr);
 void queue_pte_unpin(unsigned long ptr);
-
+void queue_set_ldt(unsigned long ptr, unsigned long bytes);
 #define PT_UPDATE_DEBUG 0
 
 #if PT_UPDATE_DEBUG > 0
@@ -119,6 +120,10 @@ extern page_update_debug_t update_debug_queue[];
  printk("PTE UNPIN %s %d: %08lx\n", __FILE__, __LINE__, (_p));    \
  queue_pte_unpin(_p);                                             \
 })   
+#define queue_set_ldt(_p,_l) ({                                        \
+ printk("SETL LDT %s %d: %08lx %d\n", __FILE__, __LINE__, (_p), (_l)); \
+ queue_set_ldt((_p), (_l));                                            \
+})   
 #endif
 
 void _flush_page_update_queue(void);
index ad07796f95f13f2e462870e51c9f295d845f37aa..cdf5319f486d1b7c03b18550533d24fb59ca2064 100644 (file)
@@ -34,7 +34,6 @@ extern pgd_t *cur_pgd;
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, struct task_struct *tsk, unsigned cpu)
 {
-       cli(); /* protect flush_update_queue multicall */
        if (prev != next) {
                /* stop flush ipis for the previous mm */
                clear_bit(cpu, &prev->cpu_vm_mask);
@@ -52,7 +51,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
                /* Re-load page tables */
                cur_pgd = next->pgd;
                queue_pt_switch(__pa(cur_pgd));
-               MULTICALL_flush_page_update_queue();
        }
 #ifdef CONFIG_SMP
        else {
@@ -74,8 +72,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, str
 #define activate_mm(prev, next) \
 do { \
        switch_mm((prev),(next),NULL,smp_processor_id()); \
-       execute_multicall_list(); \
-       sti(); /* matches 'cli' in switch_mm() */ \
+       flush_page_update_queue(); \
 } while ( 0 )
 
 #endif
index 6dec5340174220c8a74af08ef0dbd6e354bb5e09..49d6e30b2a92bba5fe5caed0481ba9d255cd3ae4 100644 (file)
@@ -73,19 +73,13 @@ out_oom:
 static inline pgd_t *get_pgd_slow(void)
 {
        pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
-       pgd_t *kpgd;
-       pmd_t *kpmd;
-       pte_t *kpte;
 
        if (pgd) {
                memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t));
                memcpy(pgd + USER_PTRS_PER_PGD,
                        init_mm.pgd + USER_PTRS_PER_PGD,
                        (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
-               kpgd = pgd_offset_k((unsigned long)pgd);
-               kpmd = pmd_offset(kpgd, (unsigned long)pgd);
-               kpte = pte_offset(kpmd, (unsigned long)pgd);
-               queue_l1_entry_update(__pa(kpte), (*(unsigned long *)kpte)&~_PAGE_RW);
+                __make_page_readonly(pgd);
                queue_pgd_pin(__pa(pgd));
 
        }
@@ -117,14 +111,8 @@ static inline void free_pgd_slow(pgd_t *pgd)
                free_page((unsigned long)__va(pgd_val(pgd[i])-1));
        kmem_cache_free(pae_pgd_cachep, pgd);
 #else
-       pgd_t *kpgd;
-       pmd_t *kpmd;
-       pte_t *kpte;
        queue_pgd_unpin(__pa(pgd));
-       kpgd = pgd_offset_k((unsigned long)pgd);
-       kpmd = pmd_offset(kpgd, (unsigned long)pgd);
-       kpte = pte_offset(kpmd, (unsigned long)pgd);
-       queue_l1_entry_update(__pa(kpte), (*(unsigned long *)kpte)|_PAGE_RW);
+        __make_page_writeable(pgd);
        free_page((unsigned long)pgd);
 #endif
 }
@@ -141,18 +129,12 @@ static inline void free_pgd_fast(pgd_t *pgd)
 static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 {
     pte_t *pte;
-    pgd_t *kpgd;
-    pmd_t *kpmd;
-    pte_t *kpte;
 
     pte = (pte_t *) __get_free_page(GFP_KERNEL);
     if (pte)
     {
         clear_page(pte);
-        kpgd = pgd_offset_k((unsigned long)pte);
-        kpmd = pmd_offset(kpgd, (unsigned long)pte);
-        kpte = pte_offset(kpmd, (unsigned long)pte);
-        queue_l1_entry_update(__pa(kpte), (*(unsigned long *)kpte)&~_PAGE_RW);
+        __make_page_readonly(pte);
         queue_pte_pin(__pa(pte));
     }
     return pte;
@@ -172,14 +154,8 @@ static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm,
 
 static __inline__ void pte_free_slow(pte_t *pte)
 {
-    pgd_t *kpgd;
-    pmd_t *kpmd;
-    pte_t *kpte;
     queue_pte_unpin(__pa(pte));
-    kpgd = pgd_offset_k((unsigned long)pte);
-    kpmd = pmd_offset(kpgd, (unsigned long)pte);
-    kpte = pte_offset(kpmd, (unsigned long)pte);
-    queue_l1_entry_update(__pa(kpte), (*(unsigned long *)kpte)|_PAGE_RW);
+    __make_page_writeable(pte);
     free_page((unsigned long)pte);
 }
 
index 3cc0e90ae562f32a0b3433e0fc2c287879404603..0f914c7c424f212fcb96b2b0c72500f3dbd872dc 100644 (file)
@@ -99,6 +99,7 @@ extern void pgtable_cache_init(void);
 #ifndef __ASSEMBLY__
 /* 4MB is just a nice "safety zone". Also, we align to a fresh pde. */
 #define VMALLOC_OFFSET (4*1024*1024)
+extern void * high_memory;
 #define VMALLOC_START  (((unsigned long) high_memory + 2*VMALLOC_OFFSET-1) & \
                                                ~(VMALLOC_OFFSET-1))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
@@ -291,6 +292,71 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 struct page;
 int change_page_attr(struct page *, int, pgprot_t prot);
 
+static inline void __make_page_readonly(void *va)
+{
+    pgd_t *pgd = pgd_offset_k((unsigned long)va);
+    pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+    pte_t *pte = pte_offset(pmd, (unsigned long)va);
+    queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)&~_PAGE_RW);
+}
+
+static inline void __make_page_writeable(void *va)
+{
+    pgd_t *pgd = pgd_offset_k((unsigned long)va);
+    pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+    pte_t *pte = pte_offset(pmd, (unsigned long)va);
+    queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)|_PAGE_RW);
+}
+
+static inline void make_page_readonly(void *va)
+{
+    pgd_t *pgd = pgd_offset_k((unsigned long)va);
+    pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+    pte_t *pte = pte_offset(pmd, (unsigned long)va);
+    queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)&~_PAGE_RW);
+    if ( (unsigned long)va >= VMALLOC_START )
+        __make_page_readonly(machine_to_virt(
+            *(unsigned long *)pte&PAGE_MASK));
+}
+
+static inline void make_page_writeable(void *va)
+{
+    pgd_t *pgd = pgd_offset_k((unsigned long)va);
+    pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+    pte_t *pte = pte_offset(pmd, (unsigned long)va);
+    queue_l1_entry_update(__pa(pte), (*(unsigned long *)pte)|_PAGE_RW);
+    if ( (unsigned long)va >= VMALLOC_START )
+        __make_page_writeable(machine_to_virt(
+            *(unsigned long *)pte&PAGE_MASK));
+}
+
+static inline void make_pages_readonly(void *va, unsigned int nr)
+{
+    while ( nr-- != 0 )
+    {
+        make_page_readonly(va);
+        va = (void *)((unsigned long)va + PAGE_SIZE);
+    }
+}
+
+static inline void make_pages_writeable(void *va, unsigned int nr)
+{
+    while ( nr-- != 0 )
+    {
+        make_page_writeable(va);
+        va = (void *)((unsigned long)va + PAGE_SIZE);
+    }
+}
+
+static inline unsigned long arbitrary_virt_to_phys(void *va)
+{
+    pgd_t *pgd = pgd_offset_k((unsigned long)va);
+    pmd_t *pmd = pmd_offset(pgd, (unsigned long)va);
+    pte_t *pte = pte_offset(pmd, (unsigned long)va);
+    unsigned long pa = (*(unsigned long *)pte) & PAGE_MASK;
+    return pa | ((unsigned long)va & (PAGE_SIZE-1));
+}
+
 #endif /* !__ASSEMBLY__ */
 
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
index f21e0d7f2d616ea580a7094b4ee4890f8053e18a..86b0020c2316d35f532861b6ea510511ce94cc26 100644 (file)
@@ -381,7 +381,7 @@ struct thread_struct {
        0,0,0,0, /* esp,ebp,esi,edi */                          \
        0,0,0,0,0,0, /* es,cs,ss */                             \
        0,0,0,0,0,0, /* ds,fs,gs */                             \
-       __LDT(0),0, /* ldt */                                   \
+       0,0, /* ldt */                                          \
        0, INVALID_IO_BITMAP_OFFSET, /* tace, bitmap */         \
        {~0, } /* ioperm */                                     \
 }